package com.msk.framework.web.service;

import com.msk.common.constant.Constants;
import com.msk.common.constant.UserConstants;
import com.msk.common.core.domain.R;
import com.msk.common.core.domain.entity.SysUser;
import com.msk.common.core.domain.model.LoginUser;
import com.msk.common.core.redis.RedisCache;
import com.msk.common.exception.user.CaptchaException;
import com.msk.common.exception.user.CaptchaExpireException;
import com.msk.common.utils.*;
import com.msk.common.utils.ip.IpUtils;
import com.msk.framework.manager.AsyncManager;
import com.msk.framework.manager.factory.AsyncFactory;
import com.msk.message.service.ISmsClientService;
import com.msk.sys.domain.User;
import com.msk.sys.service.SystemService;
import com.msk.sys.utils.DictMskUtils;
import com.msk.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @Description 小程序登录服务
 * @Author zlf
 * @Date 2023/5/9 16:41
 */
@Service
public class SysMpLoginService {

    @Autowired
    private TokenService tokenService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private ISysUserService userService;

    @Autowired
    private SystemService systemService;

    @Autowired
    private ISmsClientService smsClientService;

    /**
     * 密码登录验证
     *
     * @param phone 手机号
     * @param password 密码
     * @param loginType 登录方式 1.账号密码，2.手机号验证码
     * @param loginObject 登录对象 0.平台 1.司机 2.货主 3.承运商
     * @return 结果
     */
    public R<?> passwordLogin(String phone, String password, String loginObject) {
        String username = phone;
        if (StringUtils.isAnyEmpty(username, password, loginObject)) {
            return R.appFail(2001, "登录账号/密码/登录对象必须填写");
        }
        // 用户名不在指定范围内 错误
        if (phone.length() != UserConstants.PHONE_MIN_LENGTH) {
            return R.appFail(2001, "手机号范围错误");
        }
        User user = null;
        try {
            user = systemService.getByMobile(phone, loginObject);
            if (StringUtils.isNull(user)) {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(phone, Constants.LOGIN_FAIL, MessageUtils.message("user.not.exists")));
                return R.appFail(2003, MessageUtils.message("user.not.exists"));
            } else {
                boolean checkPwd = SecurityUtils.matchesMskPassword(password, user.getPassword());
                if (!checkPwd) {
                    AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
                    return R.appFail(2002, MessageUtils.message("user.password.not.match"));
                }
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(phone, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
                LoginUser loginUser = new LoginUser();
                loginUser.setLoginId(user.getId());
                loginUser.setLoginObject(loginObject);
                loginUser.setPhone(phone);
                loginUser.setUsername(user.getLoginName());
                loginUser.setOpenId(user.getOpenid());
                recordMskLoginInfo(user);
                // 生成token
                String token = tokenService.createMpToken(loginUser);
                return R.appOk(token, "生成token成功");
            }
        } catch (Exception e) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
            e.printStackTrace();
        }
        // 生成token
        return R.appFail(2000, "系统异常");
    }

    /**
     * 验证码登录验证
     *
     * @param username 用户名
     * @param code 验证码
     * @param loginObject 登录对象 0.平台 1.司机 2.货主 3.承运商
     * @return 结果
     */
    public R<?> phoneCodeMpLogin(String phone, String code, String loginObject) {
        if (StringUtils.isAnyEmpty(phone, code, loginObject)) {
            return R.appFail(2001, "登录账号/验证码/登录对象必须填写");
        }
        // 用户名不在指定范围内 错误
        if (phone.length() != UserConstants.PHONE_MIN_LENGTH) {
            return R.appFail(2001, "手机号范围错误");
        }
        User user = null;
        try {
            //验证码开关0:开，1关
            String validateCodeSwitch = DictMskUtils.getDictLabel("1","validate_code_switch","0");
            if ("1".equals(validateCodeSwitch)) {
                if (!"9999".equals(code)) {
                    AsyncManager.me().execute(AsyncFactory.recordLogininfor(phone, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
                    return R.appFail(2002, MessageUtils.message("user.jcaptcha.error"));
                }
            } else {
                String phoneCodeCache = smsClientService.getPhoneCodeCache(phone);
                if (StringUtils.isNotEmpty(phoneCodeCache)) {
                    if (!code.equals(phoneCodeCache)) {
                        AsyncManager.me().execute(AsyncFactory.recordLogininfor(phone, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
                        return R.appFail(2002, MessageUtils.message("user.jcaptcha.error"));
                    }
                } else {
                    AsyncManager.me().execute(AsyncFactory.recordLogininfor(phone, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
                    return R.appFail(2002, MessageUtils.message("user.jcaptcha.expire"));
                }
            }
            user = systemService.getByMobile(phone, loginObject);
            if (StringUtils.isNull(user)) {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(phone, Constants.LOGIN_FAIL, MessageUtils.message("user.not.exists")));
                return R.appFail(2003, MessageUtils.message("user.not.exists"));
            }
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(phone, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
            LoginUser loginUser = new LoginUser();
            loginUser.setLoginId(user.getId());
            loginUser.setLoginObject(loginObject);
            loginUser.setPhone(phone);
            loginUser.setUsername(user.getLoginName());
            loginUser.setOpenId(user.getOpenid());
            recordMskLoginInfo(user);
            // 生成token
            String token = tokenService.createMpToken(loginUser);
            return R.appOk(token, "生成token成功");
        } catch (Exception e) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(phone, Constants.LOGIN_FAIL, e.getMessage()));
            e.printStackTrace();
        }
        // 生成token
        return R.appFail(2000, "系统异常");
    }

    /**
     * 小程序手机号登录
     * @param phone
     * @param openId
     * @param loginObject
     * @return
     */
    public R<?> phoneMpLogin(String phone, String openId, String loginObject) {
        if (StringUtils.isAnyBlank(phone, openId, loginObject)) {
            return R.appFail(2001, "登录账号/微信openId/登录对象必须填写");
        }

        // 用户名不在指定范围内 错误
        if (phone.length() != UserConstants.PHONE_MIN_LENGTH) {
            return R.appFail(2001, "手机号范围错误");
        }
        try {
            // 查询用户信息
            User user = systemService.getByMobile(phone, loginObject);
            if (StringUtils.isNull(user)) {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(phone, Constants.LOGIN_FAIL, MessageUtils.message("user.not.exists")));
                return R.appFail(2003, MessageUtils.message("user.not.exists"));
            }
            //验证手机号绑定openId是否正确
            String openIdDb = user.getOpenid();
            if (StringUtils.isNotEmpty(openIdDb) && !openId.equals(openIdDb)) {
                return R.appFail(2002,  "登录账号绑定微信小程序错误");
            }
            LoginUser loginUser = new LoginUser();
            loginUser.setLoginId(user.getId());
            loginUser.setLoginObject(loginObject);
            loginUser.setPhone(phone);
            loginUser.setUsername(user.getLoginName());
            loginUser.setOpenId(user.getOpenid());
            recordMskLoginInfo(user);
            // 生成token
            String token = tokenService.createMpToken(loginUser);
            return R.appOk(token, "生成token成功");
        } catch (Exception e) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(phone, Constants.LOGIN_FAIL, e.getMessage()));
            e.printStackTrace();
        }
        // 生成token
        return R.appFail(2000, "系统异常");
    }

    /**
     * 校验验证码
     *
     * @param username 用户名
     * @param code 验证码
     * @param uuid 唯一标识
     * @return 结果
     */
    public void validateCaptcha(String username, String code, String uuid)
    {
        String verifyKey = Constants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
        String captcha = redisCache.getCacheObject(verifyKey);
        redisCache.deleteObject(verifyKey);
        if (captcha == null) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
            throw new CaptchaExpireException();
        }
        if (!code.equalsIgnoreCase(captcha)) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
            throw new CaptchaException();
        }
    }

    /**
     * 记录登录信息
     *
     * @param userId 用户ID
     */
    public void recordLoginInfo(Long userId) {
        SysUser sysUser = new SysUser();
        sysUser.setUserId(userId);
        sysUser.setLoginIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
        sysUser.setLoginDate(DateUtils.getNowDate());
        userService.updateUserProfile(sysUser);
    }

    /**
     * 记录登录信息
     * @param user
     */
    public void recordMskLoginInfo(User user) {
        systemService.updateUserLoginInfo(user);
    }

    /**
     * 小程序退出
     */
    public void mpLogout() {
        tokenService.delMpLoginUser();
    }
}
